package com.prawn.information.service;

import java.util.*;
import java.util.concurrent.TimeUnit;

import com.prawn.information.dao.ExpertsArticlesDao;
import com.prawn.information.dto.InformationDTO;
import com.prawn.information.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import util.IdWorker;

import com.prawn.information.dao.InformationDao;
import com.prawn.information.pojo.Information;

/**
 * 服务层
 *
 * @author Administrator
 */
@Service
public class InformationService {

    @Autowired
    private InformationDao informationDao;

    @Autowired
    private ExpertsArticlesDao expertsArticlesDao;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 增加
     *
     * @param information
     */
    public void add(Information information) {
        information.setId(idWorker.nextId() + "");
        information.setCreationTime(new Date());
        informationDao.save(information);
    }

    /**
     * 增加专家技术文章
     *
     * @param information
     */
    public void addDiseaseArticles(Information information) {
        information.setCreationTime(new Date());
        informationDao.save(information);
    }

    /**
     * 修改
     *
     * @param information
     */
    public void update(Information information) {
        informationDao.save(information);
    }

    /**
     * 删除
     *
     * @param id
     */
    public void deleteById(String id) {
        Optional<Information> information = informationDao.findByIdAndState(id, 1);
        information.get().setState(0);
        informationDao.save(information.get());
    }

    public List<InformationDTO> findAll(int module) {
        List<Information> list = informationDao.findByModuleAndState(module, 1);
        return changeToDto(list);
    }

    public Optional<Information> findById(String informationId) {
        return informationDao.findByIdAndState(informationId, 1);
    }

    public Information findById(String id, String ip) {
        //key序列化方式;（不然会出现乱码;）,但是如果方法上有Long等非String类型的话，会报类型转换错误；
        //所以在没有自己定义key生成策略的时候，以下这个代码建议不要这么写，可以不配置或者自己实现ObjectRedisSerializer
        //或者JdkSerializationRedisSerializer序列化方式;
//        RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
//        redisTemplate.setKeySerializer(redisSerializer);
//        redisTemplate.setValueSerializer(redisSerializer);
//        if (!redisTemplate.hasKey(ip + "-" + id))
//            redisTemplate.opsForValue().set(ip + "-" + id, "1");

        //改动
        //ip访问文章id记录，设置一天过期时间,并给阅读量加1
        if (!redisUtil.hasKey(ip + ":" + id)) {
            redisUtil.set(ip + ":" + id, "1", 1, TimeUnit.DAYS);
            redisUtil.hincr("clickInfo", id, 1);
        }

        return informationDao.findByIdAndState(id, 1).get();
    }

    public Information findByIdAll(String informationId) {
        return informationDao.findById(informationId).get();
    }

    public Information findByIdAll(String id, String ip) {
        //ip访问文章id记录，设置一天过期时间,并给阅读量加1
        if (!redisUtil.hasKey(ip + ":" + id)) {
            redisUtil.set(ip + ":" + id, "1", 1, TimeUnit.DAYS);
            redisUtil.hincr("clickInfo", id, 1);
        }
        return informationDao.findById(id).get();
    }

    public Information findById(int state, String informationId) {
        return informationDao.findByIdAndState(informationId, state).get();
    }

    public Page<InformationDTO> findByTypeId(int module, String typeId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndTypeIdAndStateOrderByCreationTimeDesc(module, typeId, 1, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findAll(int module, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndState(module, 1, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findDelete(int module, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndState(module, 0, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findAll(int state, int module, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndState(module, state, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findByTime(int module, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndStateOrderByCreationTimeDesc(module, 1, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findByRecommend(int module, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndStateAndRecommendTrue(module, 1, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findByClickNum(int module, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndStateOrderByClickNumDesc(module, 1, pageable);
        return change2DTOPage(list, pageable);
    }

    public List<InformationDTO> findByTime(int module) {
        List<Information> list = informationDao.findByModuleAndStateOrderByCreationTimeDesc(module, 1);
        return changeToDto(list);
    }

    public List<InformationDTO> findByRecommend(int module) {
        List<Information> list = informationDao.findByModuleAndStateAndRecommendTrue(module, 1);
        return changeToDto(list);
    }

    public List<InformationDTO> findByClickNum(int module) {
        List<Information> list = informationDao.findByModuleAndStateOrderByClickNumDesc(module, 1);
        return changeToDto(list);
    }

    public List<InformationDTO> findByClickWeekly(int module) {
        List<Information> list = informationDao.findByClickWeekly(module, 1);
        return changeToDto(list);
    }

    public List<InformationDTO> findByClickMonthly(int module) {
        List<Information> list = informationDao.findByClickMonthly(module, 1);
        return changeToDto(list);
    }

    public Page<InformationDTO> findByClickWeekly(int module, int page, int size) {
        List<Information> list = informationDao.findByClickWeekly(module, 1, page -1, size);
        return changeToPage(changeToDto(list), page, size);
    }

    public Page<InformationDTO> findByClickMonthly(int module, int page, int size) {
        List<Information> list = informationDao.findByClickMonthly(module, 1, page - 1, size);
        return changeToPage(changeToDto(list), page, size);
    }

    public Page<InformationDTO> findByClickAndType(int module, String typeId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndStateAndTypeIdOrderByClickNumDesc(module, 1, typeId, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findByTypeIdAndTime(int module, String typeId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Information> list = informationDao.findByModuleAndStateAndTypeIdOrderByCreationTimeDesc(module, 1, typeId, pageable);
        return change2DTOPage(list, pageable);
    }

    public Page<InformationDTO> findByExperts(String expertsId, int page, int size) {
        List<String> informationsId = expertsArticlesDao.findByExpertsId(expertsId);
        List<Information> list = informationDao.findByIdList(informationsId);
        return changeToPage(changeToDto(list), page, size);
    }

    private List<InformationDTO> changeToDto(List<Information> informationList) {
        List<InformationDTO> list = new ArrayList<>();
        for (Information information :
                informationList) {
            InformationDTO dto = new InformationDTO();
            BeanUtils.copyProperties(information, dto);
            list.add(dto);
        }
        return list;
    }

    private Page<InformationDTO> change2DTOPage(Page<Information> informationPage, Pageable pageable) {
        List<InformationDTO> list = new LinkedList<>();
        for (Information information :
                informationPage.getContent()) {
            InformationDTO dto = new InformationDTO();
            BeanUtils.copyProperties(information, dto);
            list.add(dto);
        }
        return new PageImpl<InformationDTO>(list, pageable, informationPage.getTotalElements());
    }

    private Page<InformationDTO> changeToPage(List<InformationDTO> list, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        int start = (int) pageable.getOffset();
        int end = (start + pageable.getPageSize()) > list.size() ? list.size() : (start + pageable.getPageSize());
        return new PageImpl<InformationDTO>(list.subList(start, end), pageable, list.size());
    }
}
